Files
kokken/scripts/migrate-data-to-db.mjs
Alex Polo 570c41f465 Add comprehensive Playwright tests for calendar functionality
- Implemented tests for debugging browser cache vs server response.
- Verified calendar displays correct dates for November 2025.
- Added visual inspection screenshot for calendar layout.
- Created tests to ensure calendar fits within its container.
- Checked for correct styling of available and blocked dates.
- Debugged login form behavior and cookie handling.
- Added tests for forced browser refresh and cache verification.
- Conducted visual tests to compare actual calendar layout with expected.
- Enhanced logging for better traceability during test execution.
2025-11-07 14:09:22 +01:00

147 lines
4.9 KiB
JavaScript

import mysql from 'mysql2/promise';
import dotenv from 'dotenv';
import { readFile } from 'fs/promises';
dotenv.config();
// Read and parse data.ts
const dataFile = await readFile('./src/config/data.ts', 'utf-8');
const dataMatch = dataFile.match(/export const data = ({[\s\S]*?});?\s*$/m);
if (!dataMatch) {
throw new Error('Could not parse data.ts');
}
// Simple eval to get the data object (safe in this context)
const data = eval(`(${dataMatch[1]})`);
const connection = await mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
console.log('=== Migrating Data to Database ===\n');
try {
// 1. Migrate menus
console.log(`Migrating ${data.menus.length} menus...`);
for (const menu of data.menus) {
await connection.execute(`
INSERT INTO menus (
id, title, description, courses, sides, tags, image, featured,
base_ingredients_per_cover, ingredients_cost_index, base_labour_hours,
incremental_labour_per_cover, min_covers, lead_time_days, base_price_per_cover
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
title = VALUES(title),
description = VALUES(description),
courses = VALUES(courses),
sides = VALUES(sides),
tags = VALUES(tags),
image = VALUES(image),
featured = VALUES(featured),
base_ingredients_per_cover = VALUES(base_ingredients_per_cover),
ingredients_cost_index = VALUES(ingredients_cost_index),
base_labour_hours = VALUES(base_labour_hours),
incremental_labour_per_cover = VALUES(incremental_labour_per_cover),
min_covers = VALUES(min_covers),
lead_time_days = VALUES(lead_time_days),
base_price_per_cover = VALUES(base_price_per_cover)
`, [
menu.id,
menu.title,
menu.description,
JSON.stringify(menu.courses),
JSON.stringify(menu.sides || []),
JSON.stringify(menu.tags || []),
menu.image || null,
menu.featured || false,
menu.baseIngredientsPerCover || null,
menu.ingredientsCostIndex || 1.0,
menu.baseLabourHours || 4,
menu.incrementalLabourPerCover || 0.05,
menu.minCovers || 10,
menu.leadTimeDays || 7,
menu.basePricePerCover || 0
]);
// Migrate ingredients for this menu
if (menu.ingredients && menu.ingredients.length > 0) {
// Delete existing ingredients first
await connection.execute('DELETE FROM menu_ingredients WHERE menu_id = ?', [menu.id]);
for (let i = 0; i < menu.ingredients.length; i++) {
const ing = menu.ingredients[i];
await connection.execute(`
INSERT INTO menu_ingredients (menu_id, name, quantity, per_cover, sort_order)
VALUES (?, ?, ?, ?, ?)
`, [
menu.id,
ing.name,
ing.quantity,
ing.perCover !== false,
i
]);
}
console.log(`${menu.title} (${menu.ingredients.length} ingredienser)`);
} else {
console.log(`${menu.title} (ingen ingredienser)`);
}
}
console.log(`\n${data.menus.length} menus migreret!\n`);
// 2. Migrate packages
console.log(`Migrating ${data.packages.length} packages...`);
for (const pkg of data.packages) {
await connection.execute(`
INSERT INTO packages (
id, name, menu_id, price_per_cover, min_covers, max_covers,
includes, upsells, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
menu_id = VALUES(menu_id),
price_per_cover = VALUES(price_per_cover),
min_covers = VALUES(min_covers),
max_covers = VALUES(max_covers),
includes = VALUES(includes),
upsells = VALUES(upsells),
notes = VALUES(notes)
`, [
pkg.id,
pkg.name,
pkg.menuId,
pkg.pricePerCover,
pkg.minCovers || 10,
pkg.maxCovers || null,
JSON.stringify(pkg.includes || []),
JSON.stringify(pkg.upsells || []),
pkg.notes || null
]);
console.log(`${pkg.name} (${pkg.menuId})`);
}
console.log(`\n${data.packages.length} packages migreret!\n`);
// 3. Show summary
const [menuCount] = await connection.execute('SELECT COUNT(*) as count FROM menus');
const [ingredientCount] = await connection.execute('SELECT COUNT(*) as count FROM menu_ingredients');
const [packageCount] = await connection.execute('SELECT COUNT(*) as count FROM packages');
console.log('=== Database Summary ===');
console.log(`Menus: ${menuCount[0].count}`);
console.log(`Ingredients: ${ingredientCount[0].count}`);
console.log(`Packages: ${packageCount[0].count}`);
console.log('\n✅ Migration complete!');
} catch (error) {
console.error('❌ Migration failed:', error);
process.exit(1);
} finally {
await connection.end();
}