hana-cli
Version:
HANA Developer Command Line Interface
391 lines (341 loc) • 10.3 kB
JavaScript
// @ts-check
import * as baseLite from '../utils/base-lite.js'
import { buildDocEpilogue } from '../utils/doc-linker.js'
export const command = 'tableGroups [action] [groupName]'
export const aliases = ['tg', 'tablegroup', 'groups', 'groups-tables']
export const describe = baseLite.bundle.getText("tableGroups")
export const builder = (yargs) => yargs.options(baseLite.getBuilder({
action: {
alias: ['a'],
type: 'string',
default: 'list',
desc: baseLite.bundle.getText("tableGroupAction")
},
groupName: {
alias: ['g', 'group'],
type: 'string',
desc: baseLite.bundle.getText("tableGroupName")
},
schema: {
alias: ['s'],
type: 'string',
default: '**CURRENT_SCHEMA**',
desc: baseLite.bundle.getText("tableGroupSchema")
},
table: {
alias: ['t'],
type: 'string',
desc: baseLite.bundle.getText("tableGroupTable")
},
type: {
type: 'string',
desc: 'Table group type'
},
subtype: {
type: 'string',
desc: 'Table group subtype'
},
matchSchema: {
type: 'string',
desc: 'Match schema pattern'
},
matchTable: {
type: 'string',
desc: 'Match table pattern'
},
limit: {
alias: ['l'],
type: 'number',
default: 200,
desc: baseLite.bundle.getText("limit")
},
profile: {
alias: ['p'],
type: 'string',
desc: baseLite.bundle.getText("profile")
}
})).wrap(160).example('hana-cli tableGroups --action list --schema MYSCHEMA', baseLite.bundle.getText('tableGroupsExample')).wrap(160).epilog(buildDocEpilogue('tableGroups', 'schema-tools', ['tables', 'objects']))
export let inputPrompts = {
action: {
description: baseLite.bundle.getText("tableGroupAction"),
type: 'string',
required: false
},
groupName: {
description: baseLite.bundle.getText("tableGroupName"),
type: 'string',
required: false
},
schema: {
description: baseLite.bundle.getText("tableGroupSchema"),
type: 'string',
required: false
},
table: {
description: baseLite.bundle.getText("tableGroupTable"),
type: 'string',
required: false
},
limit: {
description: baseLite.bundle.getText("limit"),
type: 'number',
required: false
}
}
/**
* 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, handleTableGroups, inputPrompts)
}
/**
* Route to appropriate table group action
* @param {object} prompts - Input prompts with action and parameters
* @returns {Promise<void>}
*/
export async function handleTableGroups(prompts) {
const base = await import('../utils/base.js')
base.debug('handleTableGroups')
const action = (prompts.action || 'list').toLowerCase()
try {
base.setPrompts(prompts)
const db = await base.createDBConnection()
switch (action) {
case 'list':
await listTableGroups(db, prompts)
break
case 'create':
await createTableGroupAction(db, prompts)
break
case 'drop':
await dropTableGroupAction(db, prompts)
break
case 'add_table':
case 'addtable':
await addTableToGroup(db, prompts)
break
case 'remove_table':
case 'removetable':
await removeTableFromGroup(db, prompts)
break
case 'info':
await tableGroupInfo(db, prompts)
break
default:
base.output(`Unknown action: ${action}`)
base.output('Available actions: list, create, drop, add_table, remove_table, info')
break
}
base.end()
} catch (error) {
await base.error(error)
}
}
/**
* List all table groups in a schema
* @param {object} db - Database client
* @param {object} prompts - Prompts containing schema filter
* @returns {Promise<void>}
*/
async function listTableGroups(db, prompts) {
const base = await import('../utils/base.js')
base.debug('listTableGroups')
let schema = await base.dbClass.schemaCalc(prompts, db)
base.output(base.bundle.getText("log.schemaIndex", [schema, 'table groups']))
let query = `
SELECT
TABLE_GROUP_SCHEMA as SCHEMA_NAME,
TABLE_GROUP_NAME,
TABLE_GROUP_TYPE,
TABLE_GROUP_SUBTYPE,
COMMENT
FROM SYS.TABLE_GROUPS
WHERE TABLE_GROUP_SCHEMA LIKE ?
`
const params = [schema]
if (prompts.groupName && prompts.groupName !== "*") {
const groupName = base.dbClass.objectName(prompts.groupName)
query += ` AND TABLE_GROUP_NAME LIKE ?`
params.push(groupName)
} else {
query += ` AND TABLE_GROUP_NAME LIKE '%'`
}
query += ` ORDER BY TABLE_GROUP_SCHEMA, TABLE_GROUP_NAME`
const limit = base.validateLimit(prompts.limit || 200)
if (limit && base.sqlInjectionUtils.isAcceptableParameter(limit.toString())) {
query += ` LIMIT ${limit.toString()}`
}
const results = await db.statementExecPromisified(await db.preparePromisified(query), params)
base.outputTableFancy(results)
}
/**
* Create a new table group
* @param {object} db - Database client
* @param {object} prompts - Prompts with group definition
* @returns {Promise<void>}
*/
async function createTableGroupAction(db, prompts) {
const base = await import('../utils/base.js')
base.debug('createTableGroupAction')
if (!prompts.groupName) {
base.output('Group name is required to create a table group')
return
}
const groupName = base.dbClass.objectName(prompts.groupName)
let createStmt = `CREATE TABLE GROUP ${groupName}`
if (prompts.type) {
createStmt += ` TYPE ${base.dbClass.objectName(prompts.type)}`
}
if (prompts.subtype) {
createStmt += ` SUBTYPE ${base.dbClass.objectName(prompts.subtype)}`
}
base.output(`Executing: ${createStmt}`)
try {
await db.execPromisified(createStmt)
base.output(`Table group ${groupName} created successfully`)
} catch (error) {
throw error
}
}
/**
* Drop a table group
* @param {object} db - Database client
* @param {object} prompts - Prompts with group name
* @returns {Promise<void>}
*/
async function dropTableGroupAction(db, prompts) {
const base = await import('../utils/base.js')
base.debug('dropTableGroupAction')
if (!prompts.groupName) {
base.output('Group name is required to drop a table group')
return
}
const groupName = base.dbClass.objectName(prompts.groupName)
const dropStmt = `DROP TABLE GROUP ${groupName}`
base.output(`Executing: ${dropStmt}`)
try {
await db.execPromisified(dropStmt)
base.output(`Table group ${groupName} dropped successfully`)
} catch (error) {
throw error
}
}
/**
* Add a table to a table group
* @param {object} db - Database client
* @param {object} prompts - Prompts with group and table names
* @returns {Promise<void>}
*/
async function addTableToGroup(db, prompts) {
const base = await import('../utils/base.js')
base.debug('addTableToGroup')
if (!prompts.groupName) {
base.output('Group name is required')
return
}
if (!prompts.table) {
base.output('Table name is required')
return
}
const groupName = base.dbClass.objectName(prompts.groupName)
const schema = await base.dbClass.schemaCalc(prompts, db)
const tableName = base.dbClass.objectName(prompts.table)
const alterStmt = `ALTER TABLE GROUP ${groupName} ADD TABLE ${schema}.${tableName}`
base.output(`Executing: ${alterStmt}`)
try {
await db.execPromisified(alterStmt)
base.output(`Table ${schema}.${tableName} added to group ${groupName}`)
} catch (error) {
throw error
}
}
/**
* Remove a table from a table group
* @param {object} db - Database client
* @param {object} prompts - Prompts with group and table names
* @returns {Promise<void>}
*/
async function removeTableFromGroup(db, prompts) {
const base = await import('../utils/base.js')
base.debug('removeTableFromGroup')
if (!prompts.groupName) {
base.output('Group name is required')
return
}
if (!prompts.table) {
base.output('Table name is required')
return
}
const groupName = base.dbClass.objectName(prompts.groupName)
const schema = await base.dbClass.schemaCalc(prompts, db)
const tableName = base.dbClass.objectName(prompts.table)
const alterStmt = `ALTER TABLE GROUP ${groupName} REMOVE TABLE ${schema}.${tableName}`
base.output(`Executing: ${alterStmt}`)
try {
await db.execPromisified(alterStmt)
base.output(`Table ${schema}.${tableName} removed from group ${groupName}`)
} catch (error) {
throw error
}
}
/**
* Get information about a table group and its tables
* @param {object} db - Database client
* @param {object} prompts - Prompts with group name
* @returns {Promise<void>}
*/
async function tableGroupInfo(db, prompts) {
const base = await import('../utils/base.js')
base.debug('tableGroupInfo')
if (!prompts.groupName) {
base.output('Group name is required for info action')
return
}
const groupName = base.dbClass.objectName(prompts.groupName)
let schema = await base.dbClass.schemaCalc(prompts, db)
// Get table group info
let infoQuery = `
SELECT
TABLE_GROUP_SCHEMA,
TABLE_GROUP_NAME,
TABLE_GROUP_TYPE,
TABLE_GROUP_SUBTYPE,
COMMENT
FROM SYS.TABLE_GROUPS
WHERE TABLE_GROUP_SCHEMA LIKE ? AND TABLE_GROUP_NAME LIKE ?
`
const groupInfo = await db.statementExecPromisified(
await db.preparePromisified(infoQuery),
[schema, groupName]
)
if (groupInfo.length > 0) {
base.output('--- Table Group Information ---')
base.outputTableFancy(groupInfo)
} else {
base.output(`No table group found: ${schema}.${groupName}`)
return
}
// Get tables in group
let tablesQuery = `
SELECT
TABLE_SCHEMA,
TABLE_NAME
FROM SYS.TABLE_GROUP_TABLES
WHERE TABLE_GROUP_SCHEMA LIKE ? AND TABLE_GROUP_NAME LIKE ?
ORDER BY TABLE_SCHEMA, TABLE_NAME
`
const tables = await db.statementExecPromisified(
await db.preparePromisified(tablesQuery),
[schema, groupName]
)
if (tables.length > 0) {
base.output('')
base.output('--- Tables in Group ---')
base.outputTableFancy(tables)
} else {
base.output('No tables in this group')
}
}