import initSqlJs from 'sql.js'; import fs from 'fs'; import path from 'path'; import { applyRuntimeMigrations } from './schemaMigrations.js'; interface SeedIngredient { quantity?: string; unit?: string; item: string; notes?: string; } interface SeedStep { instruction: string; } interface SeedRecipe { title: string; description: string; servings: number; prep_time_minutes: number; cook_time_minutes: number; source_url: string; image_url: string; tags: string[]; ingredients: SeedIngredient[]; steps: SeedStep[]; } const DATA_DIR = path.resolve(process.cwd(), 'data'); const DB_PATH = process.env.DATABASE_PATH || path.join(DATA_DIR, 'recipes.db'); const SCHEMA_PATH = path.resolve(process.cwd(), 'src/backend/db/schema.sql'); const seedRecipes: SeedRecipe[] = [ { title: 'Spaghetti Bolognese', description: 'Rich tomato and beef sauce simmered and served over spaghetti.', servings: 4, prep_time_minutes: 15, cook_time_minutes: 50, source_url: 'https://www.bbcgoodfood.com/recipes/best-spaghetti-bolognese-recipe', image_url: 'https://images.unsplash.com/photo-1622973536968-3ead9e780960?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Pasta', 'Beef', 'Family Favorite'], ingredients: [ { quantity: '1', unit: 'lb', item: 'ground beef' }, { quantity: '1', unit: 'tbsp', item: 'olive oil' }, { quantity: '1', item: 'yellow onion', notes: 'diced' }, { quantity: '2', unit: 'cloves', item: 'garlic', notes: 'minced' }, { quantity: '28', unit: 'oz', item: 'crushed tomatoes' }, { quantity: '2', unit: 'tbsp', item: 'tomato paste' }, { quantity: '1', unit: 'tsp', item: 'dried oregano' }, { quantity: '12', unit: 'oz', item: 'spaghetti' }, { quantity: 'to taste', item: 'salt and black pepper' } ], steps: [ { instruction: 'Heat olive oil in a large pot and sauté onion for 4 to 5 minutes until softened.' }, { instruction: 'Add garlic and cook 30 seconds, then add beef and cook until browned.' }, { instruction: 'Stir in tomato paste, crushed tomatoes, oregano, salt, and pepper.' }, { instruction: 'Simmer uncovered for 35 to 40 minutes, stirring occasionally.' }, { instruction: 'Cook spaghetti in salted boiling water until al dente, then drain.' }, { instruction: 'Serve sauce over spaghetti.' } ] }, { title: 'Chicken Tacos', description: 'Quick skillet chicken tacos with lime and warm tortillas.', servings: 4, prep_time_minutes: 15, cook_time_minutes: 20, source_url: 'https://www.allrecipes.com/recipe/70935/taqueria-style-tacos-carne-asada/', image_url: 'https://images.unsplash.com/photo-1613514785940-daed07799d9b?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Mexican', 'Chicken', 'Quick'], ingredients: [ { quantity: '1.5', unit: 'lb', item: 'boneless chicken thighs', notes: 'sliced' }, { quantity: '2', unit: 'tbsp', item: 'olive oil' }, { quantity: '1', unit: 'tbsp', item: 'chili powder' }, { quantity: '1', unit: 'tsp', item: 'ground cumin' }, { quantity: '1/2', unit: 'tsp', item: 'garlic powder' }, { quantity: '8', item: 'corn tortillas' }, { quantity: '1', item: 'lime', notes: 'cut in wedges' }, { quantity: '1', unit: 'cup', item: 'shredded lettuce' }, { quantity: '1/2', unit: 'cup', item: 'salsa' } ], steps: [ { instruction: 'Toss chicken with oil, chili powder, cumin, garlic powder, and salt.' }, { instruction: 'Cook chicken in a hot skillet for 8 to 10 minutes until cooked through.' }, { instruction: 'Warm tortillas in a dry pan or microwave.' }, { instruction: 'Fill tortillas with chicken, lettuce, and salsa.' }, { instruction: 'Finish with lime juice and serve.' } ] }, { title: 'Classic Roast Chicken and Potatoes', description: 'Simple roast chicken with crispy potatoes and pan juices.', servings: 4, prep_time_minutes: 20, cook_time_minutes: 80, source_url: 'https://www.seriouseats.com/butterflied-roasted-chicken-with-quick-jus-recipe', image_url: 'https://images.unsplash.com/photo-1518492104633-130d0cc84637?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Chicken', 'Roast', 'Family Favorite'], ingredients: [ { quantity: '1', item: 'whole chicken', notes: 'about 4 pounds' }, { quantity: '2', unit: 'lb', item: 'Yukon Gold potatoes', notes: 'cut into chunks' }, { quantity: '2', unit: 'tbsp', item: 'olive oil' }, { quantity: '1', unit: 'tsp', item: 'kosher salt' }, { quantity: '1/2', unit: 'tsp', item: 'black pepper' }, { quantity: '1', unit: 'tsp', item: 'dried thyme' }, { quantity: '1', item: 'lemon', notes: 'halved' } ], steps: [ { instruction: 'Preheat oven to 425°F (220°C).' }, { instruction: 'Pat chicken dry and season inside and out with salt, pepper, and thyme.' }, { instruction: 'Toss potatoes with olive oil and a pinch of salt, then spread in a roasting pan.' }, { instruction: 'Place chicken over potatoes and add lemon halves to pan.' }, { instruction: 'Roast for 70 to 80 minutes until chicken reaches 165°F in the thickest part.' }, { instruction: 'Rest 10 minutes before carving and serving with potatoes.' } ] }, { title: 'Fudgy Brownies', description: 'Dense chocolate brownies with crackly tops.', servings: 12, prep_time_minutes: 15, cook_time_minutes: 30, source_url: 'https://sallysbakingaddiction.com/seriously-fudgy-homemade-brownies/', image_url: 'https://images.unsplash.com/photo-1606313564200-e75d5e30476f?auto=format&fit=crop&w=1600&q=80', tags: ['Dessert', 'Baking', 'Chocolate'], ingredients: [ { quantity: '10', unit: 'tbsp', item: 'unsalted butter' }, { quantity: '1 1/4', unit: 'cups', item: 'granulated sugar' }, { quantity: '3/4', unit: 'cup', item: 'cocoa powder' }, { quantity: '2', item: 'large eggs' }, { quantity: '1', unit: 'tsp', item: 'vanilla extract' }, { quantity: '1/2', unit: 'cup', item: 'all-purpose flour' }, { quantity: '1/4', unit: 'tsp', item: 'salt' }, { quantity: '1/2', unit: 'cup', item: 'chocolate chips' } ], steps: [ { instruction: 'Preheat oven to 350°F (175°C) and line an 8x8 pan with parchment.' }, { instruction: 'Melt butter, whisk in sugar and cocoa until smooth.' }, { instruction: 'Whisk in eggs one at a time, then vanilla.' }, { instruction: 'Fold in flour, salt, and chocolate chips just until combined.' }, { instruction: 'Spread batter in pan and bake 25 to 30 minutes.' }, { instruction: 'Cool completely before slicing.' } ] }, { title: 'Fluffy Buttermilk Pancakes', description: 'Classic breakfast pancakes, light and tender.', servings: 4, prep_time_minutes: 10, cook_time_minutes: 15, source_url: 'https://www.kingarthurbaking.com/recipes/buttermilk-pancakes-recipe', image_url: 'https://images.unsplash.com/photo-1528207776546-365bb710ee93?auto=format&fit=crop&w=1600&q=80', tags: ['Breakfast', 'Quick', 'Family Favorite'], ingredients: [ { quantity: '2', unit: 'cups', item: 'all-purpose flour' }, { quantity: '2', unit: 'tbsp', item: 'sugar' }, { quantity: '2', unit: 'tsp', item: 'baking powder' }, { quantity: '1/2', unit: 'tsp', item: 'baking soda' }, { quantity: '1/2', unit: 'tsp', item: 'salt' }, { quantity: '2', unit: 'cups', item: 'buttermilk' }, { quantity: '2', item: 'large eggs' }, { quantity: '3', unit: 'tbsp', item: 'melted butter' } ], steps: [ { instruction: 'Whisk dry ingredients in a large bowl.' }, { instruction: 'Whisk buttermilk, eggs, and melted butter in a second bowl.' }, { instruction: 'Pour wet into dry and stir gently until just combined.' }, { instruction: 'Cook 1/4-cup portions on a greased skillet over medium heat until bubbles form.' }, { instruction: 'Flip and cook until golden on both sides.' } ] }, { title: 'Classic Beef Chili', description: 'Hearty chili with beef, beans, tomatoes, and warm spices.', servings: 6, prep_time_minutes: 20, cook_time_minutes: 60, source_url: 'https://www.simplyrecipes.com/recipes/beef_chili/', image_url: 'https://images.unsplash.com/photo-1547592166-23ac45744acd?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Beef', 'One Pot', 'Meal Prep'], ingredients: [ { quantity: '1.5', unit: 'lb', item: 'ground beef' }, { quantity: '1', item: 'onion', notes: 'diced' }, { quantity: '1', item: 'bell pepper', notes: 'diced' }, { quantity: '3', unit: 'cloves', item: 'garlic', notes: 'minced' }, { quantity: '2', unit: 'tbsp', item: 'chili powder' }, { quantity: '1', unit: 'tsp', item: 'ground cumin' }, { quantity: '28', unit: 'oz', item: 'diced tomatoes' }, { quantity: '15', unit: 'oz', item: 'kidney beans', notes: 'drained' }, { quantity: '1', unit: 'cup', item: 'beef broth' } ], steps: [ { instruction: 'Brown beef in a large pot and drain excess fat if needed.' }, { instruction: 'Add onion, pepper, and garlic; cook until softened.' }, { instruction: 'Stir in chili powder and cumin and cook 1 minute.' }, { instruction: 'Add tomatoes, beans, broth, and salt; bring to simmer.' }, { instruction: 'Simmer uncovered 45 minutes until thickened.' } ] }, { title: 'Chicken and Vegetable Stir-Fry', description: 'Fast weeknight stir-fry with savory garlic-ginger sauce.', servings: 4, prep_time_minutes: 15, cook_time_minutes: 15, source_url: 'https://www.recipetineats.com/chicken-stir-fry/', image_url: 'https://images.unsplash.com/photo-1512058564366-18510be2db19?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Chicken', 'Quick', 'Asian-Inspired'], ingredients: [ { quantity: '1', unit: 'lb', item: 'chicken breast', notes: 'thinly sliced' }, { quantity: '2', unit: 'cups', item: 'broccoli florets' }, { quantity: '1', item: 'red bell pepper', notes: 'sliced' }, { quantity: '1', unit: 'cup', item: 'snap peas' }, { quantity: '2', unit: 'tbsp', item: 'soy sauce' }, { quantity: '1', unit: 'tbsp', item: 'oyster sauce' }, { quantity: '1', unit: 'tbsp', item: 'sesame oil' }, { quantity: '2', unit: 'cloves', item: 'garlic', notes: 'minced' }, { quantity: '1', unit: 'tsp', item: 'fresh ginger', notes: 'grated' } ], steps: [ { instruction: 'Mix soy sauce, oyster sauce, and sesame oil in a small bowl.' }, { instruction: 'Heat a wok or large skillet over high heat and cook chicken until just done.' }, { instruction: 'Add vegetables, garlic, and ginger; stir-fry 3 to 4 minutes.' }, { instruction: 'Pour in sauce and cook 1 to 2 minutes until glossy.' }, { instruction: 'Serve hot with rice.' } ] }, { title: 'Tomato Basil Soup', description: 'Creamy tomato soup finished with fresh basil.', servings: 4, prep_time_minutes: 10, cook_time_minutes: 30, source_url: 'https://www.loveandlemons.com/tomato-basil-soup-recipe/', image_url: 'https://images.unsplash.com/photo-1547592180-85f173990554?auto=format&fit=crop&w=1600&q=80', tags: ['Soup', 'Vegetarian', 'Lunch', 'One Pot'], ingredients: [ { quantity: '2', unit: 'tbsp', item: 'olive oil' }, { quantity: '1', item: 'yellow onion', notes: 'chopped' }, { quantity: '2', unit: 'cloves', item: 'garlic', notes: 'minced' }, { quantity: '28', unit: 'oz', item: 'crushed tomatoes' }, { quantity: '2', unit: 'cups', item: 'vegetable broth' }, { quantity: '1/3', unit: 'cup', item: 'heavy cream' }, { quantity: '1/4', unit: 'cup', item: 'fresh basil', notes: 'chopped' }, { quantity: 'to taste', item: 'salt and black pepper' } ], steps: [ { instruction: 'Sauté onion in olive oil until softened, about 5 minutes.' }, { instruction: 'Add garlic and cook 30 seconds.' }, { instruction: 'Add tomatoes and broth, then simmer 20 minutes.' }, { instruction: 'Blend soup until smooth using an immersion blender.' }, { instruction: 'Stir in cream and basil; season to taste and serve.' } ] }, { title: 'Creamy Baked Mac and Cheese', description: 'Comfort-food macaroni with cheddar and a crispy top.', servings: 6, prep_time_minutes: 20, cook_time_minutes: 30, source_url: 'https://www.thechunkychef.com/family-favorite-baked-mac-and-cheese/', image_url: 'https://images.unsplash.com/photo-1543339308-43e59d6b73a6?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Pasta', 'Vegetarian', 'Family Favorite'], ingredients: [ { quantity: '1', unit: 'lb', item: 'elbow macaroni' }, { quantity: '4', unit: 'tbsp', item: 'butter' }, { quantity: '1/4', unit: 'cup', item: 'all-purpose flour' }, { quantity: '3', unit: 'cups', item: 'milk' }, { quantity: '2 1/2', unit: 'cups', item: 'sharp cheddar', notes: 'shredded' }, { quantity: '1/2', unit: 'cup', item: 'parmesan', notes: 'grated' }, { quantity: '1/2', unit: 'cup', item: 'breadcrumbs' }, { quantity: 'to taste', item: 'salt and black pepper' } ], steps: [ { instruction: 'Preheat oven to 375°F (190°C). Cook macaroni until just al dente.' }, { instruction: 'Make a roux with butter and flour in a saucepan.' }, { instruction: 'Whisk in milk and cook until thickened.' }, { instruction: 'Stir in cheddar and parmesan until melted; season with salt and pepper.' }, { instruction: 'Combine sauce and macaroni, transfer to baking dish, top with breadcrumbs.' }, { instruction: 'Bake 20 minutes until bubbling and golden.' } ] }, { title: 'Chicken Caesar Salad', description: 'Romaine, grilled chicken, croutons, and parmesan with Caesar dressing.', servings: 4, prep_time_minutes: 15, cook_time_minutes: 10, source_url: 'https://www.bonappetit.com/recipe/classic-caesar-salad', image_url: 'https://images.unsplash.com/photo-1546793665-c74683f339c1?auto=format&fit=crop&w=1600&q=80', tags: ['Lunch', 'Salad', 'Chicken', 'Quick'], ingredients: [ { quantity: '2', item: 'chicken breasts' }, { quantity: '2', unit: 'heads', item: 'romaine lettuce', notes: 'chopped' }, { quantity: '1', unit: 'cup', item: 'croutons' }, { quantity: '1/2', unit: 'cup', item: 'parmesan', notes: 'shaved or grated' }, { quantity: '1/2', unit: 'cup', item: 'Caesar dressing' }, { quantity: '1', unit: 'tbsp', item: 'olive oil' }, { quantity: 'to taste', item: 'salt and black pepper' } ], steps: [ { instruction: 'Season chicken with salt and pepper, then cook in olive oil until done.' }, { instruction: 'Rest chicken for 5 minutes and slice.' }, { instruction: 'Toss romaine with Caesar dressing.' }, { instruction: 'Top salad with sliced chicken, croutons, and parmesan.' } ] }, { title: 'Vegetable Fried Rice', description: 'Weeknight fried rice with mixed vegetables and scrambled egg.', servings: 4, prep_time_minutes: 10, cook_time_minutes: 15, source_url: 'https://www.seriouseats.com/easy-vegetable-fried-rice-recipe', image_url: 'https://images.unsplash.com/photo-1603133872878-684f208fb84b?auto=format&fit=crop&w=1600&q=80', tags: ['Dinner', 'Quick', 'Vegetarian', 'Asian-Inspired'], ingredients: [ { quantity: '4', unit: 'cups', item: 'cooked jasmine rice', notes: 'day-old preferred' }, { quantity: '2', item: 'eggs', notes: 'beaten' }, { quantity: '1', unit: 'cup', item: 'frozen peas and carrots' }, { quantity: '3', item: 'green onions', notes: 'sliced' }, { quantity: '2', unit: 'tbsp', item: 'soy sauce' }, { quantity: '1', unit: 'tbsp', item: 'sesame oil' }, { quantity: '1', unit: 'tbsp', item: 'neutral oil' }, { quantity: '2', unit: 'cloves', item: 'garlic', notes: 'minced' } ], steps: [ { instruction: 'Heat neutral oil in a large skillet or wok over medium-high heat.' }, { instruction: 'Scramble eggs quickly, then transfer to a plate.' }, { instruction: 'Cook vegetables and garlic for 2 minutes.' }, { instruction: 'Add rice and stir-fry until hot and lightly crisped.' }, { instruction: 'Return eggs, then add soy sauce, sesame oil, and green onions.' }, { instruction: 'Toss to combine and serve.' } ] }, { title: 'Chewy Chocolate Chip Cookies', description: 'Classic bakery-style cookies with crisp edges and chewy centers.', servings: 24, prep_time_minutes: 15, cook_time_minutes: 12, source_url: 'https://joyfoodsunshine.com/the-most-amazing-chocolate-chip-cookies/', image_url: 'https://images.unsplash.com/photo-1499636136210-6f4ee915583e?auto=format&fit=crop&w=1600&q=80', tags: ['Dessert', 'Baking', 'Family Favorite'], ingredients: [ { quantity: '1', unit: 'cup', item: 'unsalted butter', notes: 'softened' }, { quantity: '3/4', unit: 'cup', item: 'brown sugar' }, { quantity: '1/2', unit: 'cup', item: 'granulated sugar' }, { quantity: '2', item: 'large eggs' }, { quantity: '2', unit: 'tsp', item: 'vanilla extract' }, { quantity: '2 1/4', unit: 'cups', item: 'all-purpose flour' }, { quantity: '1', unit: 'tsp', item: 'baking soda' }, { quantity: '1', unit: 'tsp', item: 'salt' }, { quantity: '2', unit: 'cups', item: 'chocolate chips' } ], steps: [ { instruction: 'Preheat oven to 375°F (190°C) and line baking sheets.' }, { instruction: 'Cream butter, brown sugar, and granulated sugar until fluffy.' }, { instruction: 'Beat in eggs and vanilla.' }, { instruction: 'Mix in flour, baking soda, and salt until just combined.' }, { instruction: 'Fold in chocolate chips.' }, { instruction: 'Scoop dough onto baking sheets and bake 10 to 12 minutes.' } ] } ]; function ensureDataDir() { if (!fs.existsSync(DATA_DIR)) { fs.mkdirSync(DATA_DIR, { recursive: true }); } } function scalar(db: any, sql: string, params: any[] = []): any { const result = db.exec(sql, params); if (!result.length || !result[0].values.length) return null; return result[0].values[0][0]; } async function seedDatabase() { ensureDataDir(); const SQL = await initSqlJs(); const db = fs.existsSync(DB_PATH) ? new SQL.Database(fs.readFileSync(DB_PATH)) : new SQL.Database(); // Ensure schema exists for empty/new DB files. const hasRecipesTable = scalar(db, "SELECT name FROM sqlite_master WHERE type='table' AND name='recipes'"); if (!hasRecipesTable) { const schema = fs.readFileSync(SCHEMA_PATH, 'utf8'); db.exec(schema); } applyRuntimeMigrations(db); let createdCount = 0; let updatedCount = 0; const ensureTagId = (name: string): number => { const existingId = scalar(db, 'SELECT id FROM tags WHERE name = ? LIMIT 1', [name]); if (existingId) return existingId as number; db.run('INSERT INTO tags (name) VALUES (?)', [name]); return scalar(db, 'SELECT last_insert_rowid()') as number; }; for (const recipe of seedRecipes) { const now = Math.floor(Date.now() / 1000); const existingId = scalar(db, 'SELECT id FROM recipes WHERE title = ? LIMIT 1', [recipe.title]) as number | null; let recipeId: number; if (existingId) { recipeId = existingId; db.run( `UPDATE recipes SET description = ?, servings = ?, prep_time_minutes = ?, cook_time_minutes = ?, source_url = ?, image_url = ?, updated_at = ? WHERE id = ?`, [ recipe.description, recipe.servings, recipe.prep_time_minutes, recipe.cook_time_minutes, recipe.source_url, recipe.image_url, now, recipeId ] ); db.run('DELETE FROM ingredients WHERE recipe_id = ?', [recipeId]); db.run('DELETE FROM steps WHERE recipe_id = ?', [recipeId]); db.run('DELETE FROM recipe_tags WHERE recipe_id = ?', [recipeId]); updatedCount += 1; } else { db.run( `INSERT INTO recipes (title, description, servings, prep_time_minutes, cook_time_minutes, source_url, image_url, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ recipe.title, recipe.description, recipe.servings, recipe.prep_time_minutes, recipe.cook_time_minutes, recipe.source_url, recipe.image_url, now, now ] ); recipeId = scalar(db, 'SELECT last_insert_rowid()') as number; createdCount += 1; } recipe.ingredients.forEach((ingredient, idx) => { db.run( 'INSERT INTO ingredients (recipe_id, position, quantity, unit, item, notes) VALUES (?, ?, ?, ?, ?, ?)', [ recipeId, idx, ingredient.quantity ?? null, ingredient.unit ?? null, ingredient.item, ingredient.notes ?? null ] ); }); recipe.steps.forEach((step, idx) => { db.run( 'INSERT INTO steps (recipe_id, position, instruction) VALUES (?, ?, ?)', [recipeId, idx, step.instruction] ); }); recipe.tags.forEach((tagName) => { const tagId = ensureTagId(tagName); db.run('INSERT INTO recipe_tags (recipe_id, tag_id) VALUES (?, ?)', [recipeId, tagId]); }); } const data = db.export(); fs.writeFileSync(DB_PATH, Buffer.from(data)); db.close(); console.log(`Seed complete. Created ${createdCount}, updated ${updatedCount}, total seed recipes ${seedRecipes.length}.`); } if (import.meta.url === `file://${process.argv[1]}`) { seedDatabase().catch((error) => { console.error('Seed failed:', error); process.exit(1); }); } export { seedDatabase, seedRecipes };