CoolFace
Apppublic

TigreHabibi/sql-empire-builder

sourceHugging Faceupdated 11mo agoView on Hugging Face
0likes
script.js403 linesDownload Raw Back to root
1// Game State2let gameState = {3    productos: [4        { id: 1, nombre: 'PlayStation 5', precio: 500, stock: 10 },5        { id: 2, nombre: 'Xbox Series X', precio: 450, stock: 8 },6        { id: 3, nombre: 'Nintendo Switch', precio: 300, stock: 15 }7    ],8    clientes: [9        { id: 1, nombre: 'Ana García', email: 'ana@email.com', pedidos: [1] },10        { id: 2, nombre: 'Carlos López', email: 'carlos@email.com', pedidos: [2] },11        { id: 3, nombre: 'María Rodríguez', email: 'maria@email.com', pedidos: [] }12    ],13    pedidos: [14        { id: 1, cliente_id: 1, producto_id: 1, cantidad: 1, fecha: '2024-01-15' },15        { id: 2, cliente_id: 2, producto_id: 2, cantidad: 1, fecha: '2024-01-16' }16    ],17    eventos: [],18    dinero: 10000,19    reputacion: 10020};21 22// Initialize game23function initGame() {24    renderTables();25    generateRandomEvent();26    startEventGenerator();27}28 29// Render database tables30function renderTables() {31    // Render productos table32    const productosTable = document.getElementById('productos-table');33    productosTable.innerHTML = gameState.productos.map(producto => `34        <tr class="border-b border-gray-700">35            <td class="p-2">${producto.id}</td>36            <td class="p-2">${producto.nombre}</td>37            <td class="p-2">$${producto.precio}</td>38            <td class="p-2 ${producto.stock < 5 ? 'text-red-400' : 'text-green-400'}">${producto.stock}</td>39        </tr>40    `).join('');41 42    // Render clientes table43    const clientesTable = document.getElementById('clientes-table');44    clientesTable.innerHTML = gameState.clientes.map(cliente => `45        <tr class="border-b border-gray-700">46            <td class="p-2">${cliente.id}</td>47            <td class="p-2">${cliente.nombre}</td>48            <td class="p-2">${cliente.email}</td>49            <td class="p-2">${cliente.pedidos.length}</td>50        </tr>51    `).join('');52 53    // Render events54    renderEvents();55}56 57// Render events panel58function renderEvents() {59    const eventsContainer = document.getElementById('events-container');60    eventsContainer.innerHTML = gameState.eventos.map(evento => `61        <div class="event-item p-3 bg-gray-700 rounded border-l-4 ${getStatusClass(evento.tipo)}">62            <div class="flex items-center justify-between">63                <span class="font-semibold">${evento.titulo}</span>64                <span class="text-xs text-gray-400">${evento.fecha}</span>65            </div>66            <p class="text-sm text-gray-300 mt-1">${evento.descripcion}</p>67        </div>68    `).join('');69}70 71// Execute SQL command72function executeSQL() {73    const sqlInput = document.getElementById('sql-input');74    const sqlResult = document.getElementById('sql-result');75    const command = sqlInput.value.trim();76    77    if (!command) {78        showResult('Por favor, escribe un comando SQL válido.', 'error');79        return;80    }81 82    try {83        const result = processSQLCommand(command);84        showResult(result.message, result.type);85        renderTables();86        87        // Generate new event after successful command88        if (result.type === 'success') {89            setTimeout(generateRandomEvent, 1000);90        }91    } catch (error) {92        showResult(`Error: ${error.message}`, 'error');93    }94    95    sqlInput.value = '';96}97// Process SQL commands98function processSQLCommand(command) {99    const upperCommand = command.toUpperCase();100    101    // INSERT command102    if (upperCommand.startsWith('INSERT INTO PRODUCTOS')) {103        return handleInsertProducto(command);104    }105    // UPDATE command106    else if (upperCommand.startsWith('UPDATE PRODUCTOS')) {107        return handleUpdateProducto(command);108    }109    // DELETE command110    else if (upperCommand.startsWith('DELETE FROM CLIENTES')) {111        return handleDeleteCliente(command);112    }113    // SELECT command (basic support)114    else if (upperCommand.startsWith('SELECT')) {115        return handleSelectCommand(command);116    }117    else {118        throw new Error('Comando SQL no reconocido. Usa INSERT, UPDATE, DELETE o SELECT.');119    }120}121// Handle INSERT INTO Productos122function handleInsertProducto(command) {123    const match = command.match(/INSERT INTO Productos\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/i);124    if (!match) {125        throw new Error('Formato INSERT incorrecto. Ejemplo: INSERT INTO Productos (nombre, precio, stock) VALUES (\"Producto\", 100, 50);');126    }127 128    const columns = match[1].split(',').map(col => col.trim());129    const values = match[2].split(',').map(val => {130        // Remove quotes and trim131        let cleaned = val.trim().replace(/^['"](.*)['"]$/, '$1');132        // Handle numeric values133        if (!isNaN(cleaned)) {134            return parseInt(cleaned);135        }136        return cleaned;137    });138    139    // Validate required columns140    const requiredColumns = ['nombre', 'precio', 'stock'];141    for (const col of requiredColumns) {142        if (!columns.includes(col)) {143            throw new Error(`Falta la columna requerida: ${col}`);144        }145    }146    147    const nuevoProducto = {148        id: Math.max(0, ...gameState.productos.map(p => p.id)) + 1,149        nombre: values[columns.indexOf('nombre')],150        precio: values[columns.indexOf('precio')],151        stock: values[columns.indexOf('stock')]152    };153 154    // Validate numeric values155    if (isNaN(nuevoProducto.precio) || isNaN(nuevoProducto.stock)) {156        throw new Error('Precio y stock deben ser números válidos');157    }158 159    if (nuevoProducto.precio <= 0 || nuevoProducto.stock < 0) {160        throw new Error('Precio debe ser mayor a 0 y stock no puede ser negativo');161    }162 163    gameState.productos.push(nuevoProducto);164    165    addEvent('Nuevo Producto', `Se ha añadido "${nuevoProducto.nombre}" al catálogo.`, 'success');166    167    return {168        message: `✅ Producto añadido exitosamente. ID: ${nuevoProducto.id}`,169        type: 'success'170    };171}172// Handle UPDATE Productos173function handleUpdateProducto(command) {174    const match = command.match(/UPDATE Productos SET (.+) WHERE (.+)/i);175    if (!match) {176        throw new Error('Formato UPDATE incorrecto. Ejemplo: UPDATE Productos SET stock = 5 WHERE id = 1;');177    }178 179    const setClause = match[1];180    const whereClause = match[2];181    182    // Simple WHERE id = X implementation183    const idMatch = whereClause.match(/id\s*=\s*(\d+)/i);184    if (!idMatch) {185        throw new Error('WHERE clause debe incluir id del producto. Ejemplo: WHERE id = 1');186    }187 188    const productoId = parseInt(idMatch[1]);189    const producto = gameState.productos.find(p => p.id === productoId);190    191    if (!producto) {192        throw new Error(`Producto con ID ${productoId} no encontrado.`);193    }194 195    let updatedFields = [];196    197    // Update fields198    if (setClause.includes('stock')) {199        const stockMatch = setClause.match(/stock\s*=\s*(\d+)/i);200        if (stockMatch) {201            const nuevoStock = parseInt(stockMatch[1]);202            if (isNaN(nuevoStock)) throw new Error('El stock debe ser un número válido.');203            if (nuevoStock < 0) throw new Error('El stock no puede ser negativo.');204            producto.stock = nuevoStock;205            updatedFields.push('stock');206        }207    }208 209    if (setClause.includes('precio')) {210        const precioMatch = setClause.match(/precio\s*=\s*(\d+)/i);211        if (precioMatch) {212            const nuevoPrecio = parseInt(precioMatch[1]);213            if (isNaN(nuevoPrecio)) throw new Error('El precio debe ser un número válido.');214            if (nuevoPrecio <= 0) throw new Error('El precio debe ser mayor a 0.');215            producto.precio = nuevoPrecio;216            updatedFields.push('precio');217        }218    }219 220    if (setClause.includes('nombre')) {221        const nombreMatch = setClause.match(/nombre\s*=\s*'([^']+)'/i) || setClause.match(/nombre\s*=\s*"([^"]+)"/i);222        if (nombreMatch) {223            producto.nombre = nombreMatch[1];224            updatedFields.push('nombre');225        }226    }227 228    if (updatedFields.length === 0) {229        throw new Error('No se encontraron campos válidos para actualizar. Usa stock, precio o nombre.');230    }231 232    addEvent('Inventario Actualizado', `Se ha actualizado el producto "${producto.nombre}". Campos: ${updatedFields.join(', ')}`, 'warning');233    234    return {235        message: `✅ Producto actualizado exitosamente. Campos modificados: ${updatedFields.join(', ')}`,236        type: 'success'237    };238}239// Handle DELETE FROM Clientes240function handleDeleteCliente(command) {241    const match = command.match(/DELETE FROM Clientes WHERE id\s*=\s*(\d+)/i);242    if (!match) {243        throw new Error('Formato DELETE incorrecto. Ejemplo: DELETE FROM Clientes WHERE id = 1;');244    }245 246    const clienteId = parseInt(match[1]);247    if (isNaN(clienteId)) {248        throw new Error('El ID del cliente debe ser un número válido.');249    }250 251    const cliente = gameState.clientes.find(c => c.id === clienteId);252    253    if (!cliente) {254        throw new Error(`Cliente con ID ${clienteId} no encontrado.`);255    }256 257    // Check for foreign key constraint (pedidos activos)258    const tienePedidos = gameState.pedidos.some(p => p.cliente_id === clienteId);259    if (tienePedidos) {260        addEvent('Error de Integridad', `No se puede eliminar al cliente "${cliente.nombre}" porque tiene pedidos activos.`, 'error');261        throw new Error('ERROR: Violación de integridad referencial. El cliente tiene pedidos asociados.');262    }263 264    gameState.clientes = gameState.clientes.filter(c => c.id !== clienteId);265    addEvent('Cliente Eliminado', `Se ha eliminado al cliente "${cliente.nombre}".`, 'warning');266    267    return {268        message: `✅ Cliente eliminado exitosamente.`,269        type: 'success'270    };271}272// Show SQL execution result273function showResult(message, type) {274    const sqlResult = document.getElementById('sql-result');275    sqlResult.className = `mt-4 p-3 rounded ${getStatusClass(type)}`;276    sqlResult.innerHTML = message;277    sqlResult.classList.remove('hidden');278    279    setTimeout(() => {280        sqlResult.classList.add('hidden');281    }, 5000);282}283 284// Get status class for styling285function getStatusClass(type) {286    switch (type) {287        case 'success': return 'status-success bg-green-900/20 border-green-500';288        case 'warning': return 'status-warning bg-yellow-900/20 border-yellow-500';289        case 'error': return 'status-error bg-red-900/20 border-red-500';290        default: return 'bg-gray-700';291    }292}293 294// Add new event295function addEvent(titulo, descripcion, tipo = 'info') {296    const evento = {297        titulo,298        descripcion,299        tipo,300        fecha: new Date().toLocaleTimeString('es-ES')301    };302    303    gameState.eventos.unshift(evento);304    if (gameState.eventos.length > 10) {305        gameState.eventos.pop();306    }307    308    renderEvents();309}310// Handle SELECT command (basic implementation)311function handleSelectCommand(command) {312    const upperCommand = command.toUpperCase();313    314    if (upperCommand.includes('FROM PRODUCTOS')) {315        let productos = [...gameState.productos];316        317        // Basic WHERE clause support318        if (upperCommand.includes('WHERE')) {319            const whereMatch = command.match(/WHERE\s+(.+)/i);320            if (whereMatch) {321                const condition = whereMatch[1].toLowerCase();322                323                if (condition.includes('stock <')) {324                    const stockValue = parseInt(condition.match(/stock\s*<\s*(\d+)/i)[1]);325                    productos = productos.filter(p => p.stock < stockValue);326                } else if (condition.includes('precio >')) {327                    const precioValue = parseInt(condition.match(/precio\s*>\s*(\d+)/i)[1]);328                    productos = productos.filter(p => p.precio > precioValue);329                } else if (condition.includes('id =')) {330                    const idValue = parseInt(condition.match(/id\s*=\s*(\d+)/i)[1]);331                    productos = productos.filter(p => p.id === idValue);332                }333            }334        }335        336        const result = productos.map(p => `ID: ${p.id}, Nombre: "${p.nombre}", Precio: ${p.precio}, Stock: ${p.stock}`).join('\n');337        return {338            message: `✅ Resultados de la consulta (${productos.length} registros):\n${result}`,339            type: 'success'340        };341    }342    else if (upperCommand.includes('FROM CLIENTES')) {343        const result = gameState.clientes.map(c => `ID: ${c.id}, Nombre: "${c.nombre}", Email: ${c.email}, Pedidos: ${c.pedidos.length}`).join('\n');344        return {345            message: `✅ Resultados de la consulta (${gameState.clientes.length} registros):\n${result}`,346            type: 'success'347        };348    }349    else {350        throw new Error('Consulta SELECT no soportada. Usa FROM Productos o FROM Clientes.');351    }352}353 354// Generate random events355function generateRandomEvent() {356    const events = [357        {358            titulo: '📦 ¡Nueva Oferta!',359            descripcion: 'Un proveedor ofrece 50 unidades de "Nintendo Switch" a precio especial.',360            tipo: 'success'361        },362        {363            titulo: '🔄 Devolución',364            descripcion: 'Un cliente devuelve una PlayStation 5. Stock actualizado.',365            tipo: 'warning'366        },367        {368            titulo: '🔥 Producto Popular',369            descripcion: 'Las ventas de Xbox Series X han aumentado. Considera aumentar el stock.',370            tipo: 'info'371        },372        {373            titulo: '⚠️ Stock Bajo',374            descripcion: 'Quedan pocas unidades de PlayStation 5. ¡Reabastece pronto!',375            tipo: 'error'376        },377        {378            titulo: '🎯 Nuevo Cliente',379            descripcion: 'Un nuevo cliente se ha registrado en tu tienda.',380            tipo: 'success'381        },382        {383            titulo: '💰 Oferta Especial',384            descripcion: 'Hoy es día de ofertas! Los clientes buscan descuentos.',385            tipo: 'info'386        }387    ];388 389    const randomEvent = events[Math.floor(Math.random() * events.length)];390    addEvent(randomEvent.titulo, randomEvent.descripcion, randomEvent.tipo);391}392// Start event generator393function startEventGenerator() {394    setInterval(() => {395        if (Math.random() > 0.7) { // 30% chance every 30 seconds396            generateRandomEvent();397        }398    }, 30000);399}400 401// Export for global access402window.executeSQL = executeSQL;403window.initGame = initGame;