#!/usr/bin/env tsx import { SkillsService } from "../services/skills-service"; import { loadSkillCategoriesFromFiles } from "../lib/skill-file-loader"; import { SkillCategory, Skill } from "../lib/types"; interface SyncStats { categoriesProcessed: number; skillsProcessed: number; newSkills: number; updatedSkills: number; skippedSkills: number; } /** * Synchronise les skills depuis les fichiers JSON vers la base de données * - Préserve les skills existantes (ne modifie que description/image) * - Ajoute uniquement les nouvelles skills * - Ne supprime jamais de skills */ async function syncSkillsToDatabase(): Promise { try { console.log("🚀 Démarrage de la synchronisation des skills..."); // Charger les skills depuis les fichiers JSON const skillCategoriesFromFiles = loadSkillCategoriesFromFiles(); console.log( `📁 ${skillCategoriesFromFiles.length} catégories trouvées dans les fichiers` ); // Récupérer les skills existantes de la base de données const existingCategories = await SkillsService.getSkillCategories(); console.log( `💾 ${existingCategories.length} catégories existantes en base` ); // Créer un map des skills existantes pour une recherche rapide const existingSkillsMap = new Map(); existingCategories.forEach((category) => { category.skills.forEach((skill) => { existingSkillsMap.set(skill.id, skill); }); }); console.log(`🔍 ${existingSkillsMap.size} skills existantes détectées`); const stats: SyncStats = { categoriesProcessed: 0, skillsProcessed: 0, newSkills: 0, updatedSkills: 0, skippedSkills: 0, }; // Synchroniser chaque catégorie for (const categoryFromFile of skillCategoriesFromFiles) { console.log( `\n📂 Traitement de la catégorie: ${categoryFromFile.category}` ); const categoryId = categoryFromFile.category.toLowerCase(); // Vérifier si la catégorie existe, sinon la créer const existingCategory = existingCategories.find( (cat) => cat.category.toLowerCase() === categoryFromFile.category.toLowerCase() ); if (!existingCategory) { console.log( ` ➕ Création de la nouvelle catégorie: ${categoryFromFile.category}` ); await SkillsService.createSkillCategory({ id: categoryId, name: categoryFromFile.category, icon: categoryFromFile.icon, }); } // Synchroniser les skills de cette catégorie for (const skillFromFile of categoryFromFile.skills) { const existingSkill = existingSkillsMap.get(skillFromFile.id); // Utiliser bulkInsertSkillsFromJSON qui gère les conflits automatiquement const needsUpdate = existingSkill ? existingSkill.description !== skillFromFile.description || existingSkill.icon !== skillFromFile.icon || JSON.stringify(existingSkill.links?.sort()) !== JSON.stringify(skillFromFile.links?.sort()) : true; if (!existingSkill) { console.log( ` ➕ Nouvelle skill: ${skillFromFile.name} (${skillFromFile.id})` ); stats.newSkills++; } else if (needsUpdate) { console.log( ` 🔄 Mise à jour de la skill: ${skillFromFile.name} (${skillFromFile.id})` ); stats.updatedSkills++; } else { console.log( ` ✅ Skill inchangée: ${skillFromFile.name} (${skillFromFile.id})` ); stats.skippedSkills++; } // Insérer/mettre à jour la skill (bulkInsert gère les conflits) await SkillsService.bulkInsertSkillsFromJSON([ { category: categoryFromFile.category, icon: categoryFromFile.icon, skills: [skillFromFile], }, ]); stats.skillsProcessed++; } stats.categoriesProcessed++; } // Afficher les statistiques finales console.log("\n📊 Statistiques de synchronisation:"); console.log(` • Catégories traitées: ${stats.categoriesProcessed}`); console.log(` • Skills traitées: ${stats.skillsProcessed}`); console.log(` • Nouvelles skills: ${stats.newSkills}`); console.log(` • Skills mises à jour: ${stats.updatedSkills}`); console.log(` • Skills inchangées: ${stats.skippedSkills}`); // Vérification finale const finalCategories = await SkillsService.getSkillCategories(); const totalSkillsInDb = finalCategories.reduce( (sum, cat) => sum + cat.skills.length, 0 ); console.log(`\n✅ Synchronisation terminée avec succès!`); console.log(`💾 Total skills en base: ${totalSkillsInDb}`); } catch (error) { console.error("❌ Erreur lors de la synchronisation:", error); process.exit(1); } } // Exécuter le script si appelé directement if (require.main === module) { syncSkillsToDatabase() .then(() => { console.log("🎉 Script terminé avec succès"); process.exit(0); }) .catch((error) => { console.error("💥 Erreur fatale:", error); process.exit(1); }); } export { syncSkillsToDatabase };