UNPKG

hana-cli

Version:
210 lines (188 loc) 5.89 kB
// @ts-check import * as baseLite from '../utils/base-lite.js' import dbClientClass from "../utils/database/index.js" import { buildDocEpilogue } from '../utils/doc-linker.js' export const command = 'dataSync' export const aliases = ['datasync', 'syncData', 'sync'] export const describe = baseLite.bundle.getText("dataSync") export const builder = (yargs) => yargs.options(baseLite.getBuilder({ sourceConnection: { alias: ['sc'], type: 'string', desc: baseLite.bundle.getText("dataSyncSourceConnection") }, targetConnection: { alias: ['tc'], type: 'string', desc: baseLite.bundle.getText("dataSyncTargetConnection") }, schema: { alias: ['s'], type: 'string', default: '**CURRENT_SCHEMA**', desc: baseLite.bundle.getText("dataSyncSchema") }, table: { alias: ['t'], type: 'string', desc: baseLite.bundle.getText("dataSyncTable") }, syncMode: { alias: ['m'], type: 'string', choices: ['full', 'incremental'], default: 'full', desc: baseLite.bundle.getText("dataSyncMode") }, batchSize: { alias: ['b'], type: 'number', default: 1000, desc: baseLite.bundle.getText("dataSyncBatchSize") }, conflictResolution: { alias: ['cr'], type: 'string', choices: ['source', 'target', 'skip'], default: 'source', desc: baseLite.bundle.getText("dataSyncConflictResolution") }, keyColumns: { alias: ['k'], type: 'string', desc: baseLite.bundle.getText("dataSyncKeyColumns") }, timeout: { alias: ['to'], type: 'number', default: 3600, desc: baseLite.bundle.getText("dataSyncTimeout") }, profile: { alias: ['p'], type: 'string', desc: baseLite.bundle.getText("profile") } })).wrap(160).example('hana-cli dataSync --sourceConnection conn1 --targetConnection conn2 --table myTable', baseLite.bundle.getText("dataSyncExample")).wrap(160).epilog(buildDocEpilogue('dataSync', 'data-tools', ['import', 'export'])) export let inputPrompts = { sourceConnection: { description: baseLite.bundle.getText("dataSyncSourceConnection"), type: 'string', required: false, ask: () => false }, targetConnection: { description: baseLite.bundle.getText("dataSyncTargetConnection"), type: 'string', required: false, ask: () => false }, schema: { description: baseLite.bundle.getText("dataSyncSchema"), type: 'string', required: false }, table: { description: baseLite.bundle.getText("dataSyncTable"), type: 'string', required: true }, syncMode: { description: baseLite.bundle.getText("dataSyncMode"), type: 'string', required: false, ask: () => false }, keyColumns: { description: baseLite.bundle.getText("dataSyncKeyColumns"), type: 'string', required: true }, timeout: { description: baseLite.bundle.getText("dataSyncTimeout"), type: 'number', required: false, default: 3600, ask: () => false }, profile: { description: baseLite.bundle.getText("profile"), type: 'string', required: false, ask: () => { } } } /** * Command handler function * @param {object} argv - Command line arguments from yargs * @returns {Promise<void>} */ export async function handler(argv) { const base = await import('../utils/base.js') base.promptHandler(argv, dataSyncMain, inputPrompts) } /** * Synchronize data between systems * @param {object} prompts - User prompts with sync options * @returns {Promise<void>} */ export async function dataSyncMain(prompts) { const base = await import('../utils/base.js') base.debug('dataSyncMain') try { base.setPrompts(prompts) // Set operation timeout const timeoutHandle = prompts.timeout > 0 ? setTimeout(() => process.exit(1), prompts.timeout * 1000) : null // Connect to database const dbClient = await dbClientClass.getNewClient(prompts) await dbClient.connect() // Get current schema let schema = prompts.schema if (schema === '**CURRENT_SCHEMA**') { const result = await dbClient.execSQL("SELECT CURRENT_SCHEMA FROM DUMMY") schema = result?.[0]?.CURRENT_SCHEMA || 'PUBLIC' } const table = prompts.table console.log(base.bundle.getText("info.startingSynchronization", [schema, table])) // Parse key columns const keyColumns = prompts.keyColumns.split(',').map(col => col.trim()) // Get source data const sourceQuery = `SELECT * FROM "${schema}"."${table}"` const sourceData = await dbClient.execSQL(sourceQuery) console.log(base.bundle.getText("info.rowsRead", [sourceData.length])) // In a full implementation, this would: // 1. Connect to target system // 2. Compare data using key columns // 3. Apply inserts/updates/deletes based on sync mode // 4. Handle conflicts according to conflictResolution strategy // 5. Process in batches according to batchSize let syncedRows = 0 const batchSize = prompts.batchSize || 1000 if (prompts.syncMode === 'full') { console.log(base.bundle.getText("info.fullSyncMode")) syncedRows = sourceData.length } else { console.log(base.bundle.getText("info.incrementalSyncMode")) // Incremental sync logic would go here syncedRows = sourceData.length } console.log(base.bundle.getText("success.syncComplete", [syncedRows, table])) if (timeoutHandle) clearTimeout(timeoutHandle) if (!prompts.quiet) { const results = [{ TABLE: table, SCHEMA: schema, SYNC_MODE: prompts.syncMode, ROWS_SYNCED: syncedRows, BATCH_SIZE: batchSize, CONFLICT_RESOLUTION: prompts.conflictResolution }] base.outputTableFancy(results) } await dbClient.disconnect() } catch (error) { base.error(base.bundle.getText("error.dataSync", [error.message])) } }