From 3fdba1fe89895cfd01051838155907011df7a42e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 06:48:19 +0000 Subject: [PATCH] feat: Add daily employee data synchronization I've added a new capability to synchronize employee data from the local database to an external database on a daily basis. Key changes: - **`worker/sync-empleados.js`**: This new script: - Connects to the local Prisma database to fetch `Cliente` records where `empleado` is true. - Provides clear placeholders and guidance for connecting to an external database (you must configure details like host, credentials, DB type, and table name, and implement specific DB client logic). - Outlines a conceptual "upsert" logic (update existing, insert new) for the external database. - Includes extensive comments on configuration, operation, and testing considerations. - **`worker/cron-worker.js`**: - I modified this to import and schedule the `syncEmpleadosToExternalDB` function from the new script. - The synchronization is scheduled to run daily at midnight. - The existing example 5-second cron job has been commented as an example. - **Documentation**: - I added in-code comments to both modified/new files to explain functionality. - `sync-empleados.js` includes sections on external DB configuration and detailed testing considerations (manual and automated). You will need to provide the actual connection details and logic for your specific external database system. --- worker/cron-worker.js | 11 +++ worker/sync-empleados.js | 169 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 worker/sync-empleados.js diff --git a/worker/cron-worker.js b/worker/cron-worker.js index ca938b3..99de80d 100644 --- a/worker/cron-worker.js +++ b/worker/cron-worker.js @@ -1,5 +1,7 @@ import cron from 'node-cron'; +import { syncEmpleadosToExternalDB } from './sync-empleados.js'; +// Example cron job, runs every 5 seconds for demonstration/testing. cron.schedule('*/5 * * * * *', () => { const now = new Date(); if (!isNaN(now)) { @@ -9,3 +11,12 @@ cron.schedule('*/5 * * * * *', () => { console.log('[cron] Fecha inválida'); } }); + +// Schedules the daily employee data synchronization to run at midnight. +cron.schedule('0 0 * * *', () => { + console.log('[CronWorker] Running daily employee synchronization task...'); + syncEmpleadosToExternalDB().catch(err => { + console.error('[CronWorker] Error during scheduled employee synchronization:', err); + }); +}); +console.log('[CronWorker] Daily employee synchronization task scheduled for 00:00.'); diff --git a/worker/sync-empleados.js b/worker/sync-empleados.js new file mode 100644 index 0000000..7b047a0 --- /dev/null +++ b/worker/sync-empleados.js @@ -0,0 +1,169 @@ +// This script is responsible for synchronizing employee data from the local +// Prisma database to an external database. It is designed to be run as a scheduled task. + +// --- External Database Configuration (PLACEHOLDERS - User MUST Configure via environment variables) --- +// IMPORTANT: These variables define the connection to your external database. +// You MUST configure these, ideally through environment variables, for the script to work. +// The script provides a template for different database types, but you'll need to: +// 1. Install the appropriate database client library (e.g., `npm install pg` or `npm install mysql2`). +// 2. Implement the actual database connection and query logic in the designated section. + +const EXTERNAL_DB_TYPE = process.env.EXTERNAL_DB_TYPE || 'your_db_type_here'; // e.g., 'postgres', 'mysql'. User must set this. +const EXTERNAL_DB_HOST = process.env.EXTERNAL_DB_HOST || 'YOUR_EXTERNAL_DB_HOST'; // User must set this. +const EXTERNAL_DB_PORT = process.env.EXTERNAL_DB_PORT || 5432; // Adjust default port if needed. User must set this. +const EXTERNAL_DB_USER = process.env.EXTERNAL_DB_USER || 'YOUR_EXTERNAL_DB_USER'; // User must set this. +const EXTERNAL_DB_PASSWORD = process.env.EXTERNAL_DB_PASSWORD || 'YOUR_EXTERNAL_DB_PASSWORD'; // User must set this. +const EXTERNAL_DB_NAME = process.env.EXTERNAL_DB_NAME || 'YOUR_EXTERNAL_DB_NAME'; // User must set this. +const EXTERNAL_DB_EMPLEADOS_TABLE = process.env.EXTERNAL_DB_EMPLEADOS_TABLE || 'empleados_externos'; // User must set this. +// --- End of External Database Configuration --- + +import { PrismaClient } from '../api/prisma/generated/client'; +const prisma = new PrismaClient(); + +async function syncEmpleadosToExternalDB() { + console.log('[SyncEmpleados] Starting synchronization process...'); + // Core logic for synchronization, wrapped in try/catch/finally to ensure + // resources like the Prisma client are properly managed (e.g., disconnected). + try { + // Fetch all 'Cliente' records from the local Prisma database that are marked as 'empleado'. + const localEmpleados = await prisma.cliente.findMany({ + where: { empleado: true }, // Filters for clients who are also employees + select: { + id: true, // Local ID, might be useful for logging/tracing + name: true, + cedula: true, + ubicacion: true, + telefono: true, + // avatar_url: true, // Add other relevant fields + // idciat: true, // Add other relevant fields + }, + }); + + if (!localEmpleados.length) { + console.log('[SyncEmpleados] No employees found in local database. Nothing to sync.'); + return; + } + console.log(`[SyncEmpleados] Found ${localEmpleados.length} employees to sync.`); + + // --- External DB Connection Logic (User to implement based on EXTERNAL_DB_TYPE) --- + // User must implement the actual database connection logic here based on EXTERNAL_DB_TYPE + // and install the required database client library (e.g., 'pg' for PostgreSQL, 'mysql2' for MySQL). + // The following are conceptual examples. + + // Example for PostgreSQL using 'pg' library (user would need to install it: npm install pg) + /* + if (EXTERNAL_DB_TYPE === 'postgres') { + // const { Client } = require('pg'); // User would uncomment and install + // const externalDbClient = new Client({ + // host: EXTERNAL_DB_HOST, + // port: EXTERNAL_DB_PORT, + // user: EXTERNAL_DB_USER, + // password: EXTERNAL_DB_PASSWORD, + // database: EXTERNAL_DB_NAME, + // }); + // await externalDbClient.connect(); + // console.log('[SyncEmpleados] Connected to external PostgreSQL database.'); + + // ... (sync logic using externalDbClient) ... + + // await externalDbClient.end(); + // console.log('[SyncEmpleados] Disconnected from external PostgreSQL database.'); + } else if (EXTERNAL_DB_TYPE === 'mysql') { + // const mysql = require('mysql2/promise'); // User would uncomment and install + // const connection = await mysql.createConnection({ + // host: EXTERNAL_DB_HOST, + // user: EXTERNAL_DB_USER, + // password: EXTERNAL_DB_PASSWORD, + // database: EXTERNAL_DB_NAME, + // port: EXTERNAL_DB_PORT, + // }); + // console.log('[SyncEmpleados] Connected to external MySQL database.'); + + // ... (sync logic using connection) ... + + // await connection.end(); + // console.log('[SyncEmpleados] Disconnected from external MySQL database.'); + } else { + console.error(`[SyncEmpleados] Unsupported EXTERNAL_DB_TYPE: ${EXTERNAL_DB_TYPE}. User needs to implement connection logic.`); + // For now, we will just log the data that would be synced + } + */ + // --- End of External DB Connection Logic --- + + console.log('[SyncEmpleados] --- Data to be Synced (Conceptual) ---'); + for (const emp of localEmpleados) { + console.log(`[SyncEmpleados] Processing employee: ID=${emp.id}, Cedula=${emp.cedula}, Name=${emp.name}`); + + // Conceptual Upsert Logic: The following section outlines where you would implement the upsert (update or insert) operation. + // You'll need to use your chosen external database client to first check if an employee + // with a matching unique identifier (e.g., emp.cedula) exists in the ${EXTERNAL_DB_EMPLEADOS_TABLE}. + // If it exists, execute an UPDATE statement. If not, execute an INSERT statement. + // Ensure you map fields from 'emp' (local employee) to the corresponding columns in your external table. + + // Example of data to be inserted/updated: + const externalData = { + // Assuming external table has these columns. User must map accordingly. + // Ensure data types are compatible between local and external databases. + cedula: emp.cedula, // Primary key for matching in the external table (assumed) + nombre: emp.name, + telefono: emp.telefono, + ubicacion: emp.ubicacion, + // local_id: emp.id, // Optional: store local ID for reference + // ... map other fields ... + }; + console.log(`[SyncEmpleados] Data for external table: ${JSON.stringify(externalData)}`); + } + console.log('[SyncEmpleados] --- End of Data to be Synced ---'); + + } catch (error) { + // Catch any errors that occur during the synchronization process. + console.error('[SyncEmpleados] Error during synchronization:', error); + } finally { + // Ensure the Prisma client is always disconnected, even if an error occurs. + await prisma.$disconnect(); + console.log('[SyncEmpleados] Prisma client disconnected.'); + } + console.log('[SyncEmpleados] Synchronization process finished.'); +} + +export { syncEmpleadosToExternalDB }; + +// --- Testing Considerations --- +// 1. **Configuration is Key:** This script requires the `EXTERNAL_DB_...` variables to be correctly +// configured with your actual external database credentials and details before any meaningful +// end-to-end testing can be performed. +// +// 2. **Manual Testing:** +// * Once configured, you can test the script by running it directly: `node worker/sync-empleados.js` +// * Observe the console logs for any errors or successful completion messages. +// * Verify that data from your local 'Cliente' table (where empleado=true) appears correctly +// in your designated external database table (`EXTERNAL_DB_EMPLEADOS_TABLE`). +// * Check that subsequent runs correctly update existing records and insert new ones. +// * The cron job in `worker/cron-worker.js` is scheduled to run this script daily at midnight. +// You can monitor logs after this time to see its execution. +// +// 3. **Automated Testing (Recommendations for future development):** +// * **Unit Tests:** +// - Mock the Prisma client (`../api/prisma/generated/client`) to return predefined employee data +// and spy on its methods. +// - Mock the external database client (e.g., `pg`, `mysql2`) to simulate connection, +// query execution (select, insert, update), and disconnections. This allows testing +// the sync logic without actual database dependencies. +// * **Integration Tests:** +// - If possible, set up a dedicated test instance of your external database. +// - Write tests that populate the local Prisma test database with sample employee data, +// run the sync script, and then query the external test database to assert that +// the data was synchronized correctly. This provides more comprehensive testing +// but requires more setup. +// +// 4. **Logging:** Pay close attention to the console output. The script includes logging for various +// stages, which will be crucial for diagnosing issues during testing and operation. +// --- End of Testing Considerations --- + +// Optional: For direct execution of this script, e.g., `node worker/sync-empleados.js` +if (require.main === module) { + console.log('[SyncEmpleados] Running synchronization script directly.'); + syncEmpleadosToExternalDB() + .then(() => console.log('[SyncEmpleados] Direct execution completed.')) + .catch(err => console.error('[SyncEmpleados] Direct execution failed:', err)); +}