Files
dtic-DIIAA/adn/tools/cli/db.rb
T

203 lines
6.9 KiB
Ruby

# frozen_string_literal: true
# adn/tools/subcomando_db.rb — Subcomando para operaciones con base de datos dtic-BITACORAs
# ==============================================================================
# Este subcomando integra las operaciones de base de datos PostgreSQL con la CLI ADN.
# Proporciona comandos para gestión de bitácoras, nodos, temas y entradas directamente
# en la base de datos, permitiendo la migración gradual desde archivos .md.
#
# Comandos disponibles:
# • adn db salud:bd — Verificar conexión y estado de la BD
# • adn db bitacora:crear [FECHA] — Crear nueva bitácora diaria
# • adn db bitacora:listar [--limit N] — Listar bitácoras existentes
# • adn db evento:crear [OPCIONES] — Crear nueva entrada cronológica
# • adn db evento:listar [OPCIONES] — Listar entradas con filtros
# • adn db nodo:crear [OPCIONES] — Crear nuevo nodo (servidor/VM/PC)
# • adn db nodo:listar [OPCIONES] — Listar nodos del sistema
# • adn db migrar:md [FECHA] — Migrar bitácora .md a base de datos
# • adn db estadisticas — Mostrar estadísticas del sistema
#
# Uso:
# ./adn/tools/run db [SUBCOMANDO] [OPCIONES]
require 'optparse'
require 'date'
require 'time'
require_relative '../core/colores'
require_relative '../core/help_formatter'
# Cargar módulo BitacorasDB
begin
require_relative '../db/core/bitacora_db'
require_relative '../db/importers/md_importer'
require_relative '../db/exporters/md_exporter'
rescue LoadError => e
# Fallback para desarrollo
puts "⚠ Advertencia: No se pudo cargar BitacoraDB o MDImporter: #{e.message}"
puts " Asegúrate de que los archivos en adn/tools/db/ existen"
end
module ADN
class SubcomandoDB
require_relative 'db/bitacora'
require_relative 'db/evento'
require_relative 'db/nodo'
require_relative 'db/ambito'
require_relative 'db/hito'
require_relative 'db/misc'
include SubcomandoDBBitacora
include SubcomandoDBEvento
include SubcomandoDBAmbito
include SubcomandoDBNodo
include SubcomandoDBHito
include SubcomandoDBMisc
# Inicializa el subcomando con argumentos y logger
#
# @param args [Array<String>] Argumentos de línea de comandos
# @param logger [ADNLogger] Instancia de logger para registro
def initialize(args, logger)
@args = args
@logger = logger
@config = cargar_configuracion
end
# Ejecuta el subcomando según los argumentos proporcionados
def ejecutar
if @args.empty? || @args[0] == 'help' || @args[0] == '-h' || @args[0] == '--help'
mostrar_ayuda
return
end
subcomando = @args[0]
sub_args = @args[1..-1] || []
case subcomando
when 'salud:bd'
comando_salud_bd
when 'bitacora:crear'
comando_bitacora_crear(sub_args)
when 'bitacora:listar'
comando_bitacora_listar(sub_args)
when 'evento:crear'
comando_evento_crear(sub_args)
when 'evento:listar'
comando_evento_listar(sub_args)
when 'evento:actualizar'
comando_evento_actualizar(sub_args)
when 'evento:eliminar'
comando_evento_eliminar(sub_args)
when 'nodo:crear'
comando_nodo_crear(sub_args)
when 'nodo:listar'
comando_nodo_listar(sub_args)
when 'nodo:actualizar'
comando_nodo_actualizar(sub_args)
when 'hito:listar'
comando_hito_listar(sub_args)
when 'hito:actualizar'
comando_hito_actualizar(sub_args)
when 'hito:renombrar'
comando_hito_renombrar(sub_args)
when 'hito:ordenar'
comando_hito_ordenar(sub_args)
when 'estadisticas'
comando_estadisticas
when 'ambito:listar'
comando_ambito_listar(sub_args)
when 'ambito:crear'
comando_ambito_crear(sub_args)
when 'ambito:info'
comando_ambito_info(sub_args)
when 'ambito:nodos'
comando_ambito_nodos(sub_args)
when 'backup'
comando_backup(sub_args)
when 'archivar:md'
comando_archivar_md
when 'migrar:sql'
comando_migrar_sql(sub_args)
else
@logger.error("Subcomando desconocido: #{subcomando}")
puts "#{Color::RED}✗ Subcomando desconocido: '#{subcomando}'#{Color::RESET}"
puts ""
mostrar_ayuda
exit 1
end
rescue Interrupt
puts "\n#{Color::YELLOW}⚠ Operación interrumpida por el usuario#{Color::RESET}"
@logger.info("Operación de base de datos interrumpida por usuario")
exit 130
rescue => e
@logger.error("Error en operación de base de datos: #{e.message}", { backtrace: e.backtrace })
puts "#{Color::RED}✗ Error: #{e.message}#{Color::RESET}"
puts "#{Color::DIM}#{e.backtrace.first}#{Color::RESET}" if ENV['ADN_DEBUG']
exit 1
end
private
def mostrar_ayuda
puts "Ayuda no disponible temporalmente. Usa: ./adn/tools/run ayuda db"
end
# ─── COMANDOS PRINCIPALES ──────────────────────────────────────────────
# ─── MÉTODOS AUXILIARES ──────────────────────────────────────────────
# Carga la configuración desde config.yml
def cargar_configuracion
config_path = File.join(__dir__, 'config.yml')
return {} unless File.exist?(config_path)
begin
YAML.load_file(config_path)
rescue => e
@logger.error("Error cargando configuración: #{e.message}")
{}
end
# Sugerir subcomandos similares basándose en distancia de Levenshtein simplificada
#
# @param subcomando [String] El subcomando ingresado por el usuario
# @return [Array<String>] Lista de subcomandos similares
def sugerir_subcomandos_similares(subcomando)
subcomandos_validos = [
'salud:bd',
'bitacora:crear',
'bitacora:listar',
'evento:crear',
'evento:listar',
'evento:actualizar',
'evento:eliminar',
'nodo:crear',
'nodo:listar',
'hito:listar',
'hito:actualizar',
'hito:renombrar',
'hito:ordenar',
'estadisticas',
'backup',
'archivar:md'
]
# Calcular distancia simple (longest common substring ratio)
similares = []
subcomandos_validos.each do |valido|
# Si empieza con las mismas letras o tiene similitud significativa
if valido.start_with?(subcomando[0, [subcomando.length, 2].min]) ||
subcomando.start_with?(valido[0, [valido.length, 2].min]) ||
(subcomando.length > 3 && valido.length > 3 &&
(valido.include?(subcomando[0,3]) || subcomando.include?(valido[0,3])))
similares << valido
end
similares.uniq
end
end
end
end
end