# frozen_string_literal: true # tools/bitacoras-db/cli/verificar_migracion.rb # ================================================ # Verifica que todas las bitácoras MD existentes estén correctamente # migradas en la base de datos. Reporta faltantes y discrepancias. # # Uso: # ruby tools/bitacoras-db/cli/verificar_migracion.rb # — o vía enjambre — # ./tools/adn/run db verificar require 'date' require_relative '../core/bitacora_db' module BitacorasDB module CLI class VerificarMigracion COLORES = { reset: "\e[0m", bold: "\e[1m", red: "\e[31m", green: "\e[32m", yellow: "\e[33m", cyan: "\e[36m", dim: "\e[2m" }.freeze def initialize(bitacoras_dir) @bitacoras_dir = bitacoras_dir @resultados = { ok: [], sin_entradas: [], no_migrada: [], sin_md: [] } end def ejecutar puts "#{COLORES[:cyan]}🔍 Verificación de migración MD ↔ DB#{COLORES[:reset]}\n\n" archivos_md = Dir.glob(File.join(@bitacoras_dir, '*.md')).sort puts "#{COLORES[:dim]}Archivos MD encontrados: #{archivos_md.size}#{COLORES[:reset]}" BitacorasDB::BitacoraDB.with_connection do |db| # 1. Validar cada MD contra la DB archivos_md.each do |archivo| fecha = File.basename(archivo, '.md') bitacora = db.find_bitacora_by_fecha(fecha) unless bitacora @resultados[:no_migrada] << fecha next end entradas = db.execute( "SELECT COUNT(*) as total FROM bitacoras.entradas WHERE bitacora_id = $1", [bitacora['id']] ) total = entradas.first['total'].to_i if total > 0 @resultados[:ok] << { fecha: fecha, entradas: total } else @resultados[:sin_entradas] << fecha end end # 2. Bitácoras en DB que no tienen MD todas_db = db.list_bitacoras(limit: 500) fechas_md = archivos_md.map { |a| File.basename(a, '.md') } todas_db.each do |b| f = b['fecha'].to_s f = f.split('T').first if f.include?('T') # por si viene con timestamp @resultados[:sin_md] << f unless fechas_md.include?(f) end end mostrar_resultados end private def mostrar_resultados puts "\n#{COLORES[:bold]}📊 Resultado de verificación:#{COLORES[:reset]}\n" # OK puts "#{COLORES[:green]}✅ Migradas correctamente: #{@resultados[:ok].size}#{COLORES[:reset]}" @resultados[:ok].each do |r| puts " #{COLORES[:dim]}#{r[:fecha]} (#{r[:entradas]} entradas)#{COLORES[:reset]}" end # Sin entradas if @resultados[:sin_entradas].any? puts "\n#{COLORES[:yellow]}⚠ En DB pero sin entradas: #{@resultados[:sin_entradas].size}#{COLORES[:reset]}" @resultados[:sin_entradas].each { |f| puts " #{f}" } end # No migradas if @resultados[:no_migrada].any? puts "\n#{COLORES[:red]}❌ No migradas (MD existe, DB no): #{@resultados[:no_migrada].size}#{COLORES[:reset]}" @resultados[:no_migrada].each { |f| puts " #{f}" } puts " #{COLORES[:dim]}Ejecuta: ./tools/adn/run db migrar:md FECHA#{COLORES[:reset]}" end # Sin MD if @resultados[:sin_md].any? puts "\n#{COLORES[:cyan]}ℹ En DB sin archivo MD: #{@resultados[:sin_md].size}#{COLORES[:reset]}" @resultados[:sin_md].each { |f| puts " #{f}" } puts " #{COLORES[:dim]}Ejecuta: ./tools/adn/run db exportar:md FECHA#{COLORES[:reset]}" end total = @resultados[:ok].size + @resultados[:sin_entradas].size total_md = @resultados[:ok].size + @resultados[:sin_entradas].size + @resultados[:no_migrada].size pct = total_md > 0 ? ((@resultados[:ok].size.to_f / total_md) * 100).round(1) : 0 puts "\n#{COLORES[:bold]}📈 Cobertura: #{pct}% (#{@resultados[:ok].size}/#{total_md})#{COLORES[:reset]}" if @resultados[:no_migrada].empty? && @resultados[:sin_entradas].empty? puts "#{COLORES[:green]}#{COLORES[:bold]}🎉 ¡Migración completa! Todas las bitácoras están en la DB.#{COLORES[:reset]}" end end end end end # Ejecución directa if __FILE__ == $0 bitacoras_dir = File.expand_path('../../../docs/bitacoras', __dir__) BitacorasDB::CLI::VerificarMigracion.new(bitacoras_dir).ejecutar end